﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using MovieModel.Json;
using MovieModel.Model;
using MovieModel.Model.Common;

namespace MovieModelTest
{
    [TestClass]
    public class MovieSerializerTest
    {
        private readonly MovieSerializer _serializer = new MovieSerializer();

        [TestMethod]
        public void ParseCompanies()
        {
            var r = new StringReader("{companies: [{\"Id\":1,\"Name\":\"blah\"}]}");
            var companies = _serializer.ParseCompanies(r);
            Assert.AreEqual(1, companies.Count);
            Assert.AreEqual("blah", companies[1].Name);
            Assert.IsNull(companies[1].ImageLocation);
            Assert.IsNull(companies[1].ThumbnailLocation);
            Assert.IsNull(companies[1].SearchMatches);
        }


        [TestMethod]
        public void ParseTags()
        {
            var r = new StringReader("{tags: [{\"Id\":1,\"Name\":\"blah\"}]}");
            var tags = _serializer.ParseTags(r);
            Assert.AreEqual(1, tags.Count);
            Assert.AreEqual("blah", tags[1].Name);
            Assert.IsNull(tags[1].ImageLocation);
            Assert.IsNull(tags[1].ThumbnailLocation);
            Assert.IsNull(tags[1].SearchMatches);


            r = new StringReader(@"{tags: [{""Id"":1,""Name"":""blah""},
                {""Id"":2,""Name"":""france"", ""SearchMatches"": [""hello"", ""world""], ""ThumbnailLocation"": ""foo"", ""ImageLocation"": ""bar""}]}");
            tags = _serializer.ParseTags(r);
            Assert.AreEqual(2, tags.Count);
            Assert.AreEqual("blah", tags[1].Name);
            Assert.AreEqual("france", tags[2].Name);
            Assert.AreEqual(2, tags[2].Id);
            Assert.IsNull(tags[1].ImageLocation);
            Assert.IsNull(tags[1].ThumbnailLocation);
            Assert.IsNull(tags[1].SearchMatches);
            Assert.AreEqual("foo", tags[2].ThumbnailLocation);
            Assert.AreEqual("bar", tags[2].ImageLocation);
            CollectionAssert.AreEquivalent(new[]{"hello", "world"}, tags[2].SearchMatches.ToArray());
        }

        [TestMethod]
        public void SaveTags()
        {
            var tags = new[]
                           {
                               new Tag
                                   {
                                       Id = 2,
                                       Name = "tag2",
                                       SearchMatches = new[] {"foo", "bar", "baz"},
                                       ImageLocation = "imageLoc"
                                   },
                               new Tag {Id = 3, Name = "another", ThumbnailLocation = "thumbLoc"}
                           };
            var sw = new StringWriter();
            _serializer.SaveTags(sw, tags);
            Console.Write(sw.ToString());
            Assert.AreEqual(@"{""tags"":[{""Id"":2,""Name"":""tag2"",""SearchMatches"":[""foo"",""bar"",""baz""]," +
                @"""ThumbnailLocation"":null,""ImageLocation"":""imageLoc""},{""Id"":3,""Name"":""another""," +
                @"""SearchMatches"":[],""ThumbnailLocation"":""thumbLoc"",""ImageLocation"":null}]}", 
                sw.ToString());
        }

        [TestMethod]
        public void SaveMovies()
        {
            var movies = new[]
                             {
                                 new Movie
                                     {
                                         Id = 1,
                                         Name = "blah",
                                         Companies = new[] {new Company {Id = 2, Name = "Pixar"}},
                                         PlayCount = 5,
                                         Runtime = 24,
                                         Year = 2009,
                                         MovieFile = new FileInfo("C:\\test"),
                                         People = new[]
                                                      {
                                                          new MoviePart(new Person {Id = 1, Name = "Tyler"},
                                                                        Role.Composer, null)
                                                      }
                                     }
                             };
            var sw = new StringWriter();
            _serializer.SaveMovies(sw, movies);
            Assert.AreEqual(@"{""movies"":[{""Id"":1,""Name"":""blah"",""SearchMatches"":[],""ThumbnailLocation"":null,""ImageLocation"":null,""MovieFile"":""C:\\test"",""Runtime"":24,""Year"":2009,""Description"":null,""Companies"":[2],""Tags"":[],""MovieParts"":[{""Person"":1,""Role"":""Composer""}]}]}",
                sw.ToString());
            
        }

        [TestMethod]
        public void ParseMovies()
        {
            var mock = new Mock<Manager>();
            mock.Setup(m => m.Tags).Returns(MakeDict(new Tag {Id = 1, Name = "Blah"}));
            mock.Setup(m => m.Companies).Returns(MakeDict(new Company {Id = 2, Name = "Pixar"}));
            mock.Setup(m => m.People).Returns(MakeDict(new Person {Id = 1, Name = "Tyler"}));
            var sr = new StringReader(@"{""movies"":[{""Id"":1,""Name"":""blah"",""SearchMatches"":[],""ThumbnailLocation"":null,""ImageLocation"":null,""MovieFile"":""C:\\test"",""Runtime"":24,""Year"":2009,""Companies"":[2],""Tags"":[],""MovieParts"":[{""Person"":1,""Role"":""Composer""}]}]}");
            var movies = _serializer.ParseMovies(sr, mock.Object);
            Assert.AreEqual(1, movies.Count);
            Assert.AreEqual(24, movies[1].Runtime);
            Assert.AreEqual("Tyler", movies[1].People.First().Person.Name);
            Assert.AreEqual(Role.Composer, movies[1].People.First().Role);
            Assert.AreSame(movies[1], movies[1].People.First().Movie);
            Assert.AreEqual("C:\\test", movies[1].MovieFile.FullName);
        }

        private static IDictionary<int, T> MakeDict<T>(params T[] items)  where T : MovieItem<T>, new()
        {
            var dict = new Dictionary<int, T>();
            foreach (T i in items)
            {
                dict[i.Id] = i;
            }
            return dict;
        }
    }
}
